/**
  * pow.js 
  * 
  * This is the main file invoke upon browser startup.
  * The server starts approximately 5 seconds after browser start.
  * 
  * David Kellogg, creator 
  * 
***/

// async_listener waits for a connection and responds to input from the network.
// The order is listen, accept connection, wait for 'GET', deliver payload,
// close connection.

// TODO Document REQUEST_HEADERS
// TODO Document system/startup.sjs
// TODO Document permalink.php
// TODO move system.startup.sjs
// TODO dir function
// TODO get_path.sjs for localhost only
// TODO pow_server.ROOT_DIRECTORY

// DONE fixed second server problem
// DONE Shutting down server does not do so cleanly -- restart impossible
// DONE startup.sjs dir fixed

/*
 *
 * Global variables. Let's keep these to a minimum.
 *
 */

var pow_serv = null; // Object for connection
var pow_icon_state = 0;
var pow_global_port = 0;
var pow_random_cookie = 0;
var pow_server;
var pow_server_active = false;

var pow_request = new Pow_Request();
var pow_response = new Pow_Response();
var pow_version = "0.1.3";
setTimeout("pow_copy_docs();", 5000);


// Should be pow_copy_docs()

/*
 *
 * Copies files after upgrade and first install.
 *
 */

function pow_copy_docs() {
	try {
		var version_number = pow_file("/pow/log/version_number");
		var first_time = false;
		if(navigator.userAgent.match(/Pow/)) {
			// Files must be copied from the default location for XULRunner ...
			var uuid = "";
			var def = "__DEFAULT_XR__";
			var ext = "";
		} else {
			// ... and Firefox
			var uuid = "{5776FCEA-FDBF-11DA-A132-001321F5C1D9}";
			var def = "__DEFAULT__";
			var ext = "/extensions/";
		}
		if( version_number.match(/^ERROR/) ) {
			pow_copy_file(def+ext+uuid+'/chrome/content/htdocs/index.sjs',
					'/pow/htdocs');
			first_time = true;
			pow_set_state(1);
		}
		if ( ! version_number.match(pow_version) || first_time  ) {
			pow_file_put_contents("/pow/log/version_number", pow_version,"w");
			pow_mkdir('/pow/data');
			pow_mkdir('/pow/htdocs/system');
			pow_copy_file(def+ext+uuid+'/chrome/content/htdocs/pow.css',
					'/pow/htdocs', true);
			pow_copy_file(def+ext+uuid+'/chrome/content/htdocs/get_path.sjs',
					'/pow/htdocs', true);
			pow_copy_file(def+ext+uuid+'/chrome/content/htdocs/help.sjs',
					'/pow/htdocs', true);
			pow_copy_file(def+ext+uuid+'/chrome/content/htdocs/md5.js',
					'/pow/htdocs', true);
			pow_copy_file(def+ext+uuid+'/chrome/content/htdocs/favicon.ico',
					'/pow/htdocs', false);
			pow_copy_file(def+ext+uuid+'/chrome/content/htdocs/LICENSE.txt',
					'/pow/htdocs', true);
			pow_copy_file(def+ext+uuid+
					'/chrome/content/htdocs/startup.sjs',
					'/pow/htdocs/system', false);
			if( navigator.userAgent.match(/Pow/)) {
				pow_copy_file(def+ext+uuid+
					'/chrome/content/htdocs/rpc.sjs',
					'/pow/htdocs/system', true);
				pow_copy_file(def+ext+uuid+
					'/chrome/content/htdocs/rpc.js',
					'/pow/htdocs/system', true);
			}
		}
		if(first_time) {
			if( ! navigator.userAgent.match(/Pow/)) {
				window.content.document.location.href = "http://localhost:6670/";
			}
		}
		if( ! version_number.match(/^ERROR/) ) {
			pow_set_state(-1);
		}
		if(gBrowser) {
			gBrowser.addEventListener("load", pow_page_load, true);
		} else {
			setTimeout("gBrowser.addEventListener('load', pow_page_load, true)", 
					10000);
		}
	} catch(e) {
		log_error(e);
	}
}

/*
 *
 * Object to hold originally requested file and directory.
 *
 */

function Pow_Request() {
	this.req_file = "";
	this.req_dir = "";
}

/*
 *
 * Object to keep track of responses. Refreshed for every request.
 *
 */

function Pow_Response() {
	this.script_out = "";
	this.exit_flag = false;
	this.content_type = "text/html";
	this.status_code = "200 OK";
	this.extra_headers = "";
	this.cookie = "";
	this.cookie_found = false;
}

/*
 *
 * Returns html for navigation for dummy Pow front page.
 *
 */

function get_pow_header(title) {
	try {
		var head = "<html>\n<head>\n<title>"+title;
		head += "</title>\n<link rel='stylesheet' href='pow.css' "+
			"type='text/css'>\n</head>\n<body>\n";
		head += "<a href='/'>Home</a> <a href='/help.sjs'>FAQ</a> "+
				"<a href='http://davidkellogg.com/wiki/Main_Page'>Help</a> ";
		var unique_userid = pow_bc_get_unique_userid();
		head +=
			"<a href='http://davidkellogg.com/infinilink/"+
			unique_userid+"/'>InfiniLink</a><br/>";
		return  head;
	} catch(e) {
		log_error(e);
	}
}

/*
 *
 * Returns client's request header based on lower-case key.
 *
 */

function pow_get_request_header(label) {
	try {
		label = label.toLowerCase();
		if(pow_server.REQUEST_HEADERS[label]) {
			return pow_server.REQUEST_HEADERS[label];
		} else {
			return "";
		}
	} catch(e) {
		log_error(e); return "";
	}
}

/*
 *
 * Rarely used ajax helper. Should not use pow_server directly.
 *
 */

function pow_run_ajax() {
	try {
		var text_out = "";
 	 	if(pow_server.GET['AJAX'] == 'true') {
 	  	var new_ar = pow_server.put_text();
 	  	pow_response.script_out += 
				"var RESPONSE = { element: '"+new_ar[0]+"', val: \""+new_ar[1]+"\"}\n";
 	  	// exit();
 	 	} else {
 	   	pow_response.script_out += "<html>\n<body>\n";
 	   	pow_response.script_out += "<script>var send_xhr=true;</script>\n";
			pow_server.xhr = pow_server.print_xhr();
			pow_response.script_out += pow_server.xhr;
 	 	}
	} catch(e) {
		log_error(e); return "";
	}
}

/*
 *
 * Evaluates a separate sjs file.
 * The file must contain <?sjs ?> markup.
 *
 */

function pow_include(filename) {
	try {
		var contents = "Content-Location: "+filename+"\r\n";
		contents += pow_file(filename);
		contents = pow_server.process_server_js(contents);
		contents = contents.replace(/Content-Location: .*\r\n/m,"");
		pow_response.script_out += contents;
	} catch (e) {
		log_error(e); return "";
	}
}

/*
 *
 * Prints pow_server variables.
 *
 */

function pow_info() {
	try {
		var info = "";
		info += "<table border='1' >";
		var request_text = pow_array_tostring(pow_server.REQUEST);
		info += "<tr><td>pow_server.REQUEST</td><td>"+
				request_text+"</td></tr>";
		var post_text = pow_array_tostring(pow_server.POST);
		info += "<tr><td>pow_server.POST</td><td>"+post_text+"</td></tr>";
		var get_text = pow_array_tostring(pow_server.GET);
		info += "<tr><td>pow_server.GET</td><td>"+get_text+"</td></tr>";
		info += "<tr><td>pow_server.REMOTE_HOST</td><td>"+
				pow_server.REMOTE_HOST+"</td></tr>";
		info += "<tr><td>pow_server.POST_FILENAME</td><td>"+
				pow_server.POST_FILENAME+"</td></tr>";
		info += "</table>";
		pow_response.script_out += info;
	} catch (e) {
		log_error(e); return "";
	}
}

/*
 *
 * Returns standard footer for Pow pages.
 *
 */

function get_pow_footer() {
	return "\n</body>\n</html>";
}

/*
 *
 * Listens for page unloads.
 * Starts pow listener after failure. This is for breadcrumbs, only.
 *
 */

function restart_pow_listener() {
	try {
		var d = window.content.document;
		var head = d.getElementsByTagName("head")[0];
		if( ! pow_is_blacklisted(d.location.href)) {
			save_pow_body(d.location.href, d.title, head.innerHTML, d.body.innerHTML);
		}
		window.content.addEventListener("unload", found_pow_unload, true ); 
	} catch(e) {
		log_error(e);
	}
}

/*
 *
 * Handles page load events to save data.
 *
 */

function pow_page_load(event) {
  if (event.originalTarget instanceof HTMLDocument) {
    if (event.originalTarget.defaultView.frameElement) {
      var doc = event.originalTarget;
      while (doc.defaultView.frameElement) {
        doc=doc.defaultView.frameElement.ownerDocument;
      }
    } else {
      var doc = event.originalTarget;
    }
  }
	if(doc.location.href.match(/\.install\.(sjs|html)$/)) {
		var inner = doc.body.innerHTML;
		var m  = inner.match(/<script>([^<>]|\n|\r)*var pow_installer = ({([^<>]|\r|\n)+});([^<>]|\r|\n)*<\/script>/);
		if(m) {
			var json = m[2];
			var m2 = json.match(/location: "(http:[^"]+)/);
			var m3 = json.match(/name: "([a-zA-Z_]+)/); //"
			var m4 = json.match(/version: "([0-9\.]+)/); //"
			var location = m2[1];
			var name = m3[1];
			var version = m4[1];
			if(location && location.match(/\.zip$/) && name && version && confirmed) {
				var confirmed = confirm("Do you want to install the POW module "+name+"?");
				var zip = pow_download_file(location);
				pow_file_put_contents("/pow/modules/staged.zip",zip,"w");
				var fh = pow_file_get_handle("/pow/modules/staged.zip");
				var unzip = Components.classes["@mozilla.org/libjar/zip-reader;1"]
 	     		 .createInstance(Components.interfaces.nsIZipReader);
				unzip.init(fh);
				unzip.open();
				var enum = unzip.findEntries("*.*");
				pow_file_put_contents("/pow/htdocs/modules/"+name+"/version.json",
						'{ "version": "'+version+'", "name": "'+name+'" }\n',"w");

				while(enum.hasMoreElements()) {
					var entry = 
							enum.getNext().QueryInterface(Components.interfaces.nsIZipEntry);
					if(name && entry.name.match(/\.(sjs|html|js|gif|png|jpg|sqlite)$/)) {
						var fh_out = 
								pow_file_get_handle("/pow/htdocs/modules/"+name+"/"+entry.name);
							unzip.extract(entry.name, fh_out);
					}
				}
				unzip.close();
			}
		}
	}
}

/**
  *
  * Sets the state of the icon in FF to gray/colored
  *
  */

function pow_set_state(new_state) {
	try {
		if(! navigator.userAgent.match(/Pow/)) {
			this.statusImage = document.getElementById("pow-status-image");
			var known_state = true;
		}
    if(new_state == -1) { // Go to last known value
			if(! navigator.userAgent.match(/Pow/)) {
      	known_state = false;
			}
			pow_icon_state = pow_get_icon_state();
			new_state = pow_get_icon_state();
    }
		if(new_state == 0 || new_state == 2) {
			if(! navigator.userAgent.match(/Pow/)) {
				this.statusImage.src = "chrome://pow/skin/fire_sg.gif";
				this.statusImage.tooltipText = "POW disabled";
			}
			pow_server.serv.close();
			pow_server_active = false;
			pow_icon_state = 0;
		} else if(new_state == 1 ) {
			if(! navigator.userAgent.match(/Pow/)) {
				this.statusImage.src = "chrome://pow/skin/fire_s.gif";	
				this.statusImage.tooltipText = "POW enabled";
			}
			if(! pow_server_active) {
			    // Added by Paul
			    try {
				    pow_server = new pow_Serv();
    				pow_server.initPowsterMan();
				} catch (e) {
				    alert(tbHandler(e));
				}
				// Reset browser
				var browser = document.getElementById("powBrowser");
				var url = "http://localhost:6673/welcome";
				//browser.setAttribute("src", url);
				// End added by Paul
				
				
				pow_server.start_server();
			}
			pow_server_active = true;
			if(! navigator.userAgent.match(/Pow/)) {
				if(known_state) {
					pow_last_visited = window.content.document.location.href;
				}
			}
			pow_icon_state = 1;
		}
		pow_set_icon_state(pow_icon_state);
	} catch(e) {
		log_error(e);
	}

}

/*
 *
 * Sends current window to http://localhost:6670/
 *
 */

function pow_send_browser_home() {
	try {
		window.content.document.location.href = 
			"http://localhost:"+pow_global_port+"/";
	} catch(e) {
		log_error(e);
	}
}

/*
 *
 * Toggles server on/off from icon.
 *
 */

function pow_rotate_state() {
	try {
		pow_icon_state++;
		if(pow_icon_state > 1) {
			pow_icon_state = 0;
		}
		pow_set_state(pow_icon_state);
	} catch(e) {
		log_error(e);
	}
}

/*
 *
 * Deletes filename. If recursive is set to true, it recursively deletes all.
 *
 */

function delete_pow_file (filename, recursive) {
	try {
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
  } catch (e) {
     log_error("Permission to delete file was denied.");
  }
	try {
	var serv_dir_file = filename;
	var f =  pow_file_get_handle("/");
	f = append_pow_path(f, serv_dir_file);
  if ( f.exists() == false ) {
		return;
	}
	f.remove(recursive);
  } catch (e) {
     log_error(e);
  }
}

/*
 *
 * One of several disperate loggers.
 *
 */

function log_pow_access(access_msg) {
	pow_save_file("/pow/log/log.txt", access_msg+"\n", "wa");
}

/*
 *
 * Saves to error log, usually from an exception.
 *
 */

function log_pow_error(error_msg) {
	pow_save_file("/pow/log/error.txt", error_msg+"\n", "wa");
}

/**
 *
 * Add several directories
 * This will append to the path
 *
 */

function append_pow_path (file, path) {
	var dirs = new Array();
	var num = 0;
	while( path.match(/^[^\/]*\/.* ?/) ) {
		var next_dir = path.replace(/^([^\/]*)\/(.*)/,"$1");
		file.append(next_dir);
		path = path.replace(/^([^\/]*)\/(.*)/,"$2");
	}
	if ( path ) {
		file.append(path);
	}
	return file;
}

/*
 *
 * Closes server
 *
 */

function close_pow() {
	pow_serv.close();
}

/*
 *
 * Returns pow login form. Client should receive cookie upon success.
 *
 */

function get_pow_login_form( last_url ) {
	var form = "<form method='POST' action='"+last_url+"'>\n";
	form += "User ID:  <input type='text' name='userid'  size=20 /><br>\n";
	form += "Password: <input type='text' name='password'  size=20 />\n";
	form += "<input type='submit' value='Login' />\n";
	form += "</form><br>";
	return form;
}

/*
 *
 * Returns breadcrumbs search form.
 *
 */

function get_pow_form( query ) {
	if(query) {
		query = query.replace(/\+/g, " ");
	} else {
		query = '';
	}
	var form = "<form method='GET' action='/htdocs/search.sjs'>\n";
	form += "<input type='text' name='query' value='"+query+"' size=20 />\n";
	form += "<input type='submit' value='Search' />\n";
	form += "</form><br>";
	return form;
}

/*
 *
 * Logs access for each download.
 *
 */

function log_access(access_msg) {
	pow_save_file("/pow/log/log.txt", access_msg+"\n", "wa");
}

/*
 *
 * Second log_error function
 *
 */

function log_error(e) {
	var error_msg = e.fileName+" "+e.lineNumber+": "+e.message;
	pow_save_file("/pow/log/error.txt", error_msg+"\n", "wa");
}

